package org.smile.josql.parse;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.smile.exception.JoSQLParseException;
import org.smile.josql.Query;
import org.smile.util.RegExp;

public class JoSQLParser {
	
	private static final Logger logger=Logger.getLogger(JoSQLParser.class);
	/**
	 * 解析
	 * @param query
	 * @throws JoSQLParseException 
	 */
	public void parse(Query query) throws JoSQLParseException{
		
		String josql=query.getJosql();
		
		query.setFrom(this.getFormString(josql).trim());
		/*解析返回结果内容
		 */
		String resultStr=this.getResultString(josql);
		if(resultStr.equals("*")){
			//当为星号的时,反回结果内容不用添加
			query.setReturnAll(true);
		}else{
			List list=new ArrayList();
			RegExp reg=new RegExp(" *, *");
			String[] results=reg.split(resultStr);
			for(int i=0;i<results.length;i++){
				list.add(results[i]);
				query.setResult(list);
			}
		}
		/*
		 * 解析where子句
		 */
		String whereStr=this.getWhereString(josql);
		query.setWhere(whereStr);
	}
	/**
	 * 解析where字句结果
	 * @return
	 * @throws JoSQLParseException
	 */
	public boolean parseWhere(WhereTokener token) throws JoSQLParseException{
		
		String start=token.nextString();
		boolean result=false;
		/**
		 * 处理是操作符的情况
		 */
		if(token.isOperator(token.next())){
			token.back();
			String opt=token.nextOperator();
			String end=token.nextString();
			try{
				double s=Double.parseDouble(start);
				double e=Double.parseDouble(end);
				if(opt.equals("<")){
					result= s<e;
				}else if(opt.equals("<=")){
					result=  s<=e;
				}else if(opt.equals(">=")){
					result=  s>=e;
				}else if(opt.equals("<>")||opt.equals("!=")){
					result=  s!=e;
				}else if(opt.equals(">")){
					result=  s>e;
				}else if(opt.equals("=")||opt.equals("==")){
					result=  s==e;
				}else{
					throw token.parseError("not support opreator flag");
				}
				logger.debug("start:"+start+", opt:"+opt+",end:"+end+" result:"+result);
			}catch(Exception e){
				if(opt.equals("<")){
					result=  start.compareTo(end)<0;
				}else if(opt.equals("<=")){
					result=  start.compareTo(end)<0||start.compareTo(end)==0;
				}else if(opt.equals(">=")){
					result=  start.compareTo(end)>0||start.compareTo(end)==0;
				}else if(opt.equals("<>")||opt.equals("!=")){
					result=  start.compareTo(end)!=0;
				}else if(opt.equals(">")){
					result=  start.compareTo(end)>0;
				}else if(opt.equals("=")||opt.equals("==")){
					result=  start.compareTo(end)==0;
				}else{
					throw token.parseError("not support opreator flag");
				}
				logger.debug("start:"+start+", opt:"+opt+",end:"+end+" result:"+result);
			}
			String next=token.nextKeyWord();
			logger.debug("下一个逻辑符:"+next);
			if(next.equals("AND")){
				return result&&parseWhere(token);
			}else if(next.equals("OR")){
				return result||parseWhere(token);
			}else if(next.equals("")){
				return result;
			}
		}else{
			token.back();
			String opt=token.nextOperator();
			if(opt.equals("LIKE")){
				String end=token.nextString();
				end="^"+end+"$";
				end=end.replaceAll("%", ".*");
				end=end.replaceAll("_", ".");
				RegExp reg=new RegExp(end);
				result=  reg.test(start);
				logger.debug("start:"+start+", opt:"+opt+",end:"+end+" result:"+result);
			}else if(opt.equals("IS NULL")){
				result=  start.equals("null");
			}else if(opt.equals("IS NOT NULL")){
				result=  !start.equals("null");
			}
			String next=token.nextKeyWord();
			logger.debug("下一个逻辑符:"+next);
			if(next.equals("AND")){
				return result&&parseWhere(token);
			}else if(next.equals("OR")){
				return result||parseWhere(token);
			}else if(next.equals("")){
				return result;
			}
		}
		throw token.parseError("解析出错");
		
	}
	/**
	 * 得到反回结果的字符串
	 * @param josql
	 * @return
	 * @throws JoSQLParseException 
	 */
	private String getResultString(String josql) throws JoSQLParseException{
		RegExp regselect=new RegExp("^ *select ",false);
		RegExp regfrom=new RegExp(" +from +",false);
		String[] froms=regfrom.find(josql);
		if(froms==null){
			throw new JoSQLParseException("josql 语法错误，必须包含select ... from 语句");
		}else if(froms.length>1){
			throw new JoSQLParseException("josql 语法错误，josql 只支持一个from 的查询 ");
		}
		int start=regselect.firstIndexEnd(josql);
		if(start==-1){
			throw new JoSQLParseException("josql 语法错误，必须包含select语句,以select 开头");
		}
		return josql.substring(start,regfrom.firstIndex(josql));
	}
	
	/**
	 * 得到from源类名
	 * @param josql
	 * @return
	 * @throws JoSQLParseException
	 */
	private String getFormString(String josql) throws JoSQLParseException{
		RegExp regfrom=new RegExp(" from +",false);
		RegExp regEnd=new RegExp(" *$| where | order +by | group +by | having ");
		int start=regfrom.firstIndexEnd(josql);
		if(start==-1){
			throw new JoSQLParseException("josql 语法错误，必须包含select ... from 语句");
		}
		int end=regEnd.firstIndex(josql);
		if(end==-1){
			throw new JoSQLParseException("josql 语法错误，from 后面语法错误");
		}
		String result=josql.substring(start,end);
		if(result.indexOf(" ")>0){
			throw new JoSQLParseException("josql 语法错误，from 后面语法错误,"+result+"不是正解的源");
		}
		return result;
	}
	
	/**
	 * 得到where字句
	 * @param josql
	 * @return
	 * @throws JoSQLParseException 
	 */
	private String getWhereString(String josql) throws JoSQLParseException{
		RegExp regfrom=new RegExp(" where +",false);
		RegExp regEnd=new RegExp(" *$| order +by | group +by | having ");
		int start=regfrom.firstIndexEnd(josql);
		if(start==-1){
			return null;
		}
		int end=regEnd.firstIndex(josql);
		if(end<start){
			throw new JoSQLParseException("josql 语法错误，where 后面语法错误,where 后必须有过滤条件");
		}
		String result=josql.substring(start,end);
		return result;
	}
	/**
	 * 得到group的字段信息
	 * @param josql
	 * @return
	 * @throws JoSQLParseException
	 */
	private String getGroupString(String josql) throws JoSQLParseException{
		RegExp regfrom=new RegExp(" group +by +",false);
		RegExp regEnd=new RegExp(" *$| having ");
		int start=regfrom.firstIndexEnd(josql);
		if(start==-1){
			return null;
		}
		int end=regEnd.firstIndex(josql);
		if(end<start){
			throw new JoSQLParseException("josql 语法错误，grou by 后面语法错误,group  后必须有过滤条件");
		}
		String result=josql.substring(start,end);
		return result;
	}
}
